package com.excilys.capicsoubank.services.impl;

import java.util.List;

import org.apache.commons.lang3.ObjectUtils;
import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import com.excilys.capicsoubank.dao.AccountDao;
import com.excilys.capicsoubank.dao.TransactionDao;
import com.excilys.capicsoubank.entities.Account;
import com.excilys.capicsoubank.entities.TransactionType;
import com.excilys.capicsoubank.services.AccountService;
import com.excilys.capicsoubank.services.UserService;
import com.googlecode.ehcache.annotations.Cacheable;

/**
 * Implémentation du service gérant les comptes.
 * 
 * @author Nicolas Poirier
 */
@Service
@Transactional(readOnly = true)
public class AccountServiceImpl implements AccountService {

	@Autowired
	private AccountDao accountDao;

	@Autowired
	private TransactionDao transactionDao;

	@Autowired
	private UserService userService;

	@Override
	public List<Account> getAccountsConnectedUser() {
		return accountDao.getAccountsByUser(userService.getConnectedUser());
	}

	@Override
	public Account getAccountById(Integer accountId) {

		Assert.notNull(accountId);

		Integer userId = userService.getConnectedUser().getUserId();

		Assert.isTrue(checkAccountOwnedByUser(userId, accountId));

		Account account = accountDao.getById(accountId);

		Assert.notNull(account);

		return account;
	}

	@Override
	public long getAccountBalanceAtSpecificDate(Integer accountId, DateTime date) {

		Account account = getAccountById(accountId);

		TransactionType[] types = { TransactionType.CARD,
				TransactionType.TRANSFER };

		return account.getBalance()
				- transactionDao.getSumTransactionsByPeriodByType(account,
						date, DateTime.now(), types);
	}

	/**
	 * Retourne false si le compte n'appartient pas à l'utilisateur.
	 * 
	 * @param userId
	 *            id de l'utilisateur
	 * @param accountId
	 *            id du compte
	 * @return true si le compte appartient à l'utilisateur, false sinon
	 */
	@Cacheable(cacheName = "userServiceCache")
	private boolean checkAccountOwnedByUser(Integer userId, Integer accountId) {

		Account account = accountDao.getById(accountId);

		Assert.notNull(account);

		return ObjectUtils.equals(userId, account.getUser().getUserId());
	}
}
